﻿@page "/todo_list"
@using BlazorBoilerplate.Shared.Dto.Sample
@*@attribute [Authorize] Uncomment to Secure this page*@
@inject HttpClient Http
@inject IMatToaster matToaster

@using System.Net

<h1>Todo List - CRUD</h1>
<p>
    This Todo List demonstrates fetching data from the server and CRUD for Blazor with .NET Core API server. This example unlike most is implemented with persistent data using N-Tier design patterns.
    Check out the <a href="https://github.com/enkodellc/blazorboilerplate" target="_blank">repository to view the source.</a> If you find this helpful please contribute or <a href="https://www.paypal.me/enkodellc">donate</a> to support further development.
    Delete is Protected to Admin users only.
</p>

<MatTable Class="mat-elevation-z5" Items="@todos" LoadInitialData="true" Striped="true" FilterByColumnName="Title" DebounceMilliseconds="150" PageSize="10">
    <MatTableHeader>
        <th>
            <div style="width:135px;">
                <MatButton Icon="playlist_add" Label="New Todo" OnClick="@((e) => OpenDialog())" Raised="true"></MatButton>
            </div>
        </th>
        <th>Id</th>
        <th>Completed</th>
        <th style="min-width:180px;">Todo</th>
    </MatTableHeader>
    <MatTableRow Context="TodoRow">
        <td>
            <MatIconButton Icon="delete" OnClick="@(() => OpenDeleteDialog(TodoRow.Id))"></MatIconButton>
        </td>
        <td>@String.Format("{0:d}", TodoRow.Id)</td>
        <td><MatCheckbox class="filled-in chk-col-blue" TValue="bool" Value="@TodoRow.IsCompleted" ValueChanged="@((item) => Update(TodoRow))"></MatCheckbox></td>
        <td>@TodoRow.Title</td>
    </MatTableRow>
</MatTable>

<MatDialog @bind-IsOpen="@dialogIsOpen">
    <MatDialogTitle>Create Todo</MatDialogTitle>
    <MatDialogContent>
        <EditForm Model="@todo" OnValidSubmit="@CreateTodo">
            <DataAnnotationsValidator />
            <ValidationSummary />
            <fieldset>
                <div class="form-group">
                    <MatTextField @bind-Value="@todo.Title" Label="Title" Icon="title" IconTrailing="true" FullWidth="true" Required="true"></MatTextField>
                </div>
                <div class="form-group">
                    <MatCheckbox @bind-Value="@todo.IsCompleted" Label="Completed"></MatCheckbox>
                </div>
            </fieldset>
        </EditForm>
    </MatDialogContent>
    <MatDialogActions>
        <MatButton OnClick="@(e => { dialogIsOpen = false; })">Cancel</MatButton>
        <MatButton OnClick="@CreateTodo">Create Todo</MatButton>
    </MatDialogActions>
</MatDialog>

<MatDialog @bind-IsOpen="@deleteDialogOpen" Style="z-index:100">
    <MatDialogTitle><MatIcon Icon="warning"></MatIcon> Confirm Delete</MatDialogTitle>
    <MatDialogContent>
        Are you sure you want to delete todo "@todo.Title" ?
    </MatDialogContent>
    <MatDialogActions>
        <MatButton OnClick="@(e => { deleteDialogOpen = false; })">Cancel</MatButton>
        <MatButton OnClick="@Delete">Delete</MatButton>
    </MatDialogActions>
</MatDialog>

@code {
    bool deleteDialogOpen = false;
    bool dialogIsOpen = false;
    List<TodoDto> todos = new List<TodoDto>();
    TodoDto todo { get; set; } = new TodoDto();

    protected override async Task OnInitializedAsync()
    {
        await ReadTodos();
    }

    async Task ReadTodos()
    {
        ApiResponseDto apiResponse = await Http.GetFromJsonAsync<ApiResponseDto>("api/todo");

        if (apiResponse.StatusCode == Status200OK)
        {
            matToaster.Add(apiResponse.Message, MatToastType.Success, "Todo List Retrieved");
            todos = Newtonsoft.Json.JsonConvert.DeserializeObject<TodoDto[]>(apiResponse.Result.ToString()).ToList<TodoDto>();
        }
        else
        {
            matToaster.Add(apiResponse.Message + " : " + apiResponse.StatusCode, MatToastType.Danger, "Todo List Retrieval Failed");
        }
    }

    public async void Update(TodoDto todo)
    {
        //this updates the IsCompleted flag only
        try
        {

            todo.IsCompleted = !todo.IsCompleted;
            ApiResponseDto apiResponse = await Http.PutJsonAsync<ApiResponseDto>("api/todo", todo);

            if (!apiResponse.IsError)
            {
                matToaster.Add(apiResponse.Message, MatToastType.Success);
            }
            else
            {
                matToaster.Add(apiResponse.Message + " : " + apiResponse.StatusCode, MatToastType.Danger, "Todo Save Failed");
                todo.IsCompleted = !todo.IsCompleted; //update failed so reset IsCompleted
            }
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.Message, MatToastType.Danger, "Todo Save Failed");
            todo.IsCompleted = !todo.IsCompleted; //update failed so reset IsCompleted
        }
    }

    public async Task Delete()
    {
        try
        {
            var response = await Http.DeleteAsync("api/todo/" + todo.Id);
            if (response.StatusCode ==  (HttpStatusCode)Status200OK)
            {
                matToaster.Add("Todo Deleted", MatToastType.Success);
                todos.Remove(todo);
            }
            else
            {
                matToaster.Add("Todo Delete Failed: " + response.StatusCode, MatToastType.Danger);
            }
            deleteDialogOpen = false;
            todo = new TodoDto(); //reset todo after delete
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.Message, MatToastType.Danger, "Todo Save Failed");
        }
    }

    public void OpenDialog()
    {
        dialogIsOpen = true;
    }

    public void OpenDeleteDialog(long todoId)
    {
        todo = todos.Where(x => x.Id == todoId).SingleOrDefault();
        this.deleteDialogOpen = true;
    }

    public async Task CreateTodo()
    {
        dialogIsOpen = false;
        try
        {
            ApiResponseDto apiResponse = await Http.PostJsonAsync<ApiResponseDto>("api/todo", todo);
            if (apiResponse.StatusCode == Status200OK)
            {
                matToaster.Add(apiResponse.Message, MatToastType.Success);
                todo = Newtonsoft.Json.JsonConvert.DeserializeObject<TodoDto>(apiResponse.Result.ToString());
                todos.Add(todo);
                todo = new TodoDto(); //reset todo after insert
            }
            else
            {
                matToaster.Add(apiResponse.Message + " : " + apiResponse.StatusCode, MatToastType.Danger, "Todo Creation Failed");
            }
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.Message, MatToastType.Danger, "Todo Creation Failed");
        }
    }
}
